#include <thread>
#include <gtest/gtest.h>
#include "../vas_video.h"

using namespace vas;

void FrameHandle(const cv::Mat &i, const Channel &c, long t) {
    std::stringstream msg;
    msg << i.cols << "x" << i.rows << ":" << t << " from " << c.channel << " at " << c.url;
    VAS_INFO(msg.str());
}

void FrameHandleWithLongTime(const cv::Mat &i, const Channel &c, long t) {
    FrameHandle(i, c, t);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

void RunVideo(const Channel &c) {
    RegisterVideo(c);
    ReadVideo(c, FrameHandleWithLongTime);
    UnregisterVideo(c);
}

TEST(VideoTest, RegisterUnRegisterVideo) {
    Channel c;
    c.channel = "test";
    c.url = "test_video.mp4";
    ASSERT_NO_THROW(RegisterVideo(c));
    ASSERT_EQ(GetProcessingVideoNum(), 1);
    std::vector<Channel> channels = GetProcessingVideos();
    ASSERT_EQ(channels[0].channel, c.channel);
    ASSERT_NO_THROW(UnregisterVideo(c));
    ASSERT_EQ(GetProcessingVideoNum(), 0);
}

TEST(VideoTest, RegisterUnRegisterVideoForManyTimes) {
    Channel c;
    c.channel = "test";
    c.url = "test_video.mp4";
    ASSERT_NO_THROW(RegisterVideo(c));
    ASSERT_THROW(RegisterVideo(c), VasRuntimeError);
    ASSERT_THROW(RegisterVideo(c), VasRuntimeError);
    ASSERT_EQ(GetProcessingVideoNum(), 1);
    ASSERT_NO_THROW(UnregisterVideo(c));
    ASSERT_NO_THROW(UnregisterVideo(c));
    ASSERT_NO_THROW(UnregisterVideo(c));
    ASSERT_NO_THROW(UnregisterVideo(c));
    ASSERT_EQ(GetProcessingVideoNum(), 0);
    ASSERT_NO_THROW(UnregisterVideo(c));
    ASSERT_NO_THROW(UnregisterVideo(c));
    ASSERT_NO_THROW(UnregisterVideo(c));
}

TEST(VideoTest, ReadVideo) {
    Channel c;
    c.channel = "test";
    c.url = "test_video.mp4";
    RegisterVideo(c);
    ASSERT_NO_THROW(ReadVideo(c, FrameHandle));
    UnregisterVideo(c);
    ASSERT_EQ(GetProcessingVideoNum(), 0);
}

TEST(VideoTest, ReadWrongVideo) {
    Channel c;
    c.channel = "test";
    c.url = "Not_Exist_Video";
    RegisterVideo(c);
    ASSERT_NO_THROW(ReadVideo(c, FrameHandle));
    UnregisterVideo(c);
    ASSERT_EQ(GetProcessingVideoNum(), 0);
}

TEST(VideoTest, ReadUnregisterVideo) {
    Channel c;
    c.channel = "test";
    c.url = "test_video.mp4";

    ASSERT_THROW(ReadVideo(c, FrameHandle), VasRuntimeError);
    ASSERT_EQ(GetProcessingVideoNum(), 0);
}

TEST(VideoTest, StopVideo) {
    Channel c;
    c.channel = "test";
    c.url = "test_video.mp4";
    std::thread t1(RunVideo, c);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    ASSERT_EQ(GetProcessingVideoNum(), 1);
    StopVideo(c.channel);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    ASSERT_EQ(GetProcessingVideoNum(), 0);
    t1.join();
}

TEST(VideoTest, StopUnregisterVideo) {
    ASSERT_NO_THROW(StopVideo("Not_Exist_Video"));
}

TEST(VideoTest, StopVideoForManyTimes) {
    Channel c;
    c.channel = "test";
    c.url = "test_video.mp4";
    std::thread t1(RunVideo, c);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    ASSERT_EQ(GetProcessingVideoNum(), 1);
    StopVideo(c.channel);
    StopVideo(c.channel);
    StopVideo(c.channel);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    ASSERT_EQ(GetProcessingVideoNum(), 0);
    t1.join();
}


